package com.sybil.ot.servicio;

import com.sybil.ot.dao.EventoDAO;
import com.sybil.ot.dao.FlujoDAO;
import com.sybil.ot.dao.PasoDAO;
import com.sybil.ot.dao.ResponsablePasoDAO;
import com.sybil.ot.dominio.Evento;
import com.sybil.ot.dominio.Flujo;
import com.sybil.ot.dominio.Paso;
import com.sybil.ot.dominio.ResponsablePaso;
import java.util.ArrayList;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service("flujoServicio")
@Transactional(readOnly = true)
public class FlujoServicio {

   @Autowired
   private FlujoDAO flujoDAO;
   @Autowired
   private PasoDAO pasoDAO;
   @Autowired
   private EventoDAO eventoDAO;
   @Autowired
   private ResponsablePasoDAO responsablePasoDAO;
//   @Autowired
//   private UsuarioDAO usuarioDAO;

   private List<Paso> pasosValidados;

   public FlujoServicio() {
      this.pasosValidados = new ArrayList<Paso>();
   }

   @Transactional(readOnly = false)
   public void eliminarFlujo(String clave) {
      Flujo ordenTrabajo = flujoDAO.obtenerFlujo(clave);
      flujoDAO.eliminarFlujo(ordenTrabajo);
   }

   public List<Flujo> obtenerFlujos() {
      return flujoDAO.obtenerFlujos(false);
   }

   public List<Flujo> obtenerFlujosActivo() {
      return flujoDAO.obtenerFlujos(true);
   }

   public Flujo obtenerFlujo(String clave) {
      return flujoDAO.obtenerFlujo(clave);
   }

   public void guardar(Flujo flujo) {
      flujo.setEstatus("N");
      flujoDAO.guardarFlujo(flujo);
   }

   public void guardar(Paso paso) {
      pasoDAO.guardarPaso(paso);
   }

   public void guardar(Evento evento) {
      eventoDAO.guardarEvento(evento);
   }

   public void guardar(ResponsablePaso responsablePaso) {
      responsablePasoDAO.guardarResponsablePaso(responsablePaso);
   }

   public Paso obtenerPaso(String claveFlujo, String clavePaso) {
      return pasoDAO.obtenerPaso(claveFlujo, clavePaso);
   }

   public List<Paso> obtenerPasosFlujo(String flujo) {
      return pasoDAO.obtenerPasos(flujo);
   }
//
//   public List<Usuario> obtenerUsuarios() {
//      return usuarioDAO.obtenerUsuarios();
//   }

   public void editar(Flujo flujo) {
      flujo.setEstatus("N");
      flujoDAO.editarFlujo(flujo);
   }

   public void editar(Paso paso) {
      pasoDAO.editarPaso(paso);
   }

   public void editar(Evento evento) {
      eventoDAO.editarEvento(evento);
   }

   public Evento obtenerEvento(String claveFlujo, String clavePaso, String claveEvento) {
      return eventoDAO.obtenerEvento(claveFlujo, clavePaso, claveEvento);
   }

   public ResponsablePaso obtenerResponsable(String claveFlujo, String clavePaso, String claveUsuario) {
      return responsablePasoDAO.obtenerResponsablePaso(claveFlujo, clavePaso, claveUsuario);
   }

   public void editar(ResponsablePaso responsablePaso) {
      responsablePasoDAO.editarResponsablePaso(responsablePaso);
   }

   public String validar(String claveFlujo) {
      Flujo flujo = flujoDAO.obtenerFlujo(claveFlujo);
      String mensajeError = "";
      if (flujo == null) {
         mensajeError += "El Flujo " + claveFlujo + " no existe.<br/>";
      } else {
         List<Paso> pasos = flujo.getPasos();
         if (pasos.isEmpty()) {
            mensajeError += "El Flujo " + claveFlujo + "-" + flujo.getDescripcion() + " no tiene pasos.<br/>";
         } else {
            int contadorPasosI = 0;
            int contadorPasosM = 0;
            int contadorPasosF = 0;
            int contadorPasosFC = 0;
            for (Paso paso : pasos) {
               if ("M".equals(paso.getTipoPaso())) {
                  contadorPasosM++;
                  List<ResponsablePaso> responsablesM = paso.getResponsablesPaso();
                  int aprobadoresM = 0;
                  for (ResponsablePaso responsable : responsablesM) {
                     if ("S".equals(responsable.getEsAprobador())) {
                        aprobadoresM++;
                     }
                  }
                  if (aprobadoresM < 1) {
                     mensajeError += "El Paso Medio " + paso.getLlave().getClavePaso() + "-" + paso.getDescripcion() + " no tiene aprobadores.<br/>";
                  }
                  List<Evento> eventosM = paso.getEventos();
                  if (eventosM.isEmpty()) {
                     mensajeError += "El Paso Medio " + paso.getLlave().getClavePaso() + "-" + paso.getDescripcion() + " no tiene eventos.<br/>";
                  } else {
                     mensajeError += validarEventos(eventosM, aprobadoresM);
                  }
               } else if ("F".equals(paso.getTipoPaso())) {
                  contadorPasosF++;
                  if (!paso.getEventos().isEmpty()) {
                     mensajeError += "El Paso Final " + paso.getLlave().getClavePaso() + "-" + paso.getDescripcion() + " no debe tener eventos.<br/>";
                  }
                  if (!paso.getResponsablesPaso().isEmpty()) {
                     mensajeError += "El Paso Final " + paso.getLlave().getClavePaso() + "-" + paso.getDescripcion() + " no debe tener responsables.<br/>";
                  }
                  if ("S".equals(paso.getFinalCorrecto())) {
                     contadorPasosFC++;
                  }
               } else {
                  contadorPasosI++;
                  if (paso.getMontoAprobacion() > 0) {
                     mensajeError += "El Paso Inicial " + paso.getLlave().getClavePaso() + "-" + paso.getDescripcion() + " no debe tener monto.<br/>";
                  }
                  List<ResponsablePaso> responsablesI = paso.getResponsablesPaso();
                  int aprobadoresI = 0;
                  for (ResponsablePaso responsable : responsablesI) {
                     if ("S".equals(responsable.getEsAprobador())) {
                        aprobadoresI++;
                     }
                  }
                  if (aprobadoresI < 1) {
                     mensajeError += "El Paso Inicial " + paso.getLlave().getClavePaso() + "-" + paso.getDescripcion() + " no tiene aprobadores.<br/>";
                  }
                  List<Evento> eventosI = paso.getEventos();
                  if (eventosI.isEmpty()) {
                     mensajeError += "El Paso Inicial " + paso.getLlave().getClavePaso() + "-" + paso.getDescripcion() + " debe tener un evento.<br/>";
                  } else if (eventosI.size() > 1) {
                     mensajeError += "El Paso Inicial " + paso.getLlave().getClavePaso() + "-" + paso.getDescripcion() + " tiene mas de 1 evento.<br/>";
                  } else {
//                     mensajeError += validarEventos(eventosI, aprobadoresI);
                     if (!"U".equals(paso.getEventos().get(0).getTipoAprobacion())) {
                        mensajeError += "El evento del paso inicial " + paso.getLlave().getClavePaso() + "-" + paso.getDescripcion() + " debe ser tipo de aprobacion única.<br/>";
                     }
                  }
                  if ("".equals(mensajeError)) {
                     boolean termina = flujoTermina(paso);
                     if (!termina) {
                        mensajeError += "El Flujo " + claveFlujo + "-" + flujo.getDescripcion() + " no termina.<br/>";
                     }
                  }
               }
            }//termina el for del barrido de los pasos
            if (contadorPasosI < 1) {
               mensajeError += "El Flujo " + claveFlujo + "-" + flujo.getDescripcion() + " no tiene paso Inicial.<br/>";
            } else if (contadorPasosI > 1) {
               mensajeError += "El Flujo " + claveFlujo + "-" + flujo.getDescripcion() + " tiene mas de 1 paso Inicial.<br/>";
            }
            if (contadorPasosM < 1) {
               mensajeError += "El Flujo " + claveFlujo + "-" + flujo.getDescripcion() + " no tiene paso(s) Medios.<br/>";
            }
            if (contadorPasosF < 1) {
               mensajeError += "El Flujo " + claveFlujo + "-" + flujo.getDescripcion() + " no tiene paso(s) Final(es).<br/>";
            }
            if (contadorPasosFC != 1) {
               mensajeError += "El Flujo " + claveFlujo + "-" + flujo.getDescripcion() + " de tener uno y solo un paso Final correcto, tiene:" + contadorPasosFC + ".<br/>";
            }
         }//cierra el else cuando tiene pasos
         if ("".equals(mensajeError)) {
            if (!"A".equals(flujo.getEstatus())) {
               flujo.setEstatus("A");
               flujoDAO.editarFlujo(flujo);
            }
         } else {
            if (!"N".equals(flujo.getEstatus())) {
               flujo.setEstatus("N");
               flujoDAO.editarFlujo(flujo);
            }
         }
      }//cierra el else de nulidad del flujo
      return mensajeError;
   }

   private String validarEventos(List<Evento> eventos, int aprobadores) {
      String mensajeError = "";
      for (Evento evento : eventos) {
         if ("U".equals(evento.getTipoAprobacion())) {
            if (aprobadores > 1) {
               mensajeError += "El evento " + evento.getLlave().getClaveEvento()
                       + "-" + evento.getDescripcion() + " especifica aprobacion unica, pero tiene " + aprobadores + " aprobadores.<br/>";
            }
         } else if ("N".equals(evento.getTipoAprobacion())) {
            if (evento.getNumeroAprobadores() != aprobadores) {
               mensajeError += "El evento " + evento.getLlave().getClaveEvento()
                       + "-" + evento.getDescripcion() + " especifica aprobacion numerica por "
                       + evento.getNumeroAprobadores() + " aprobadores, pero tiene " + aprobadores + " aprobadores.<br/>";
            }
         } else {
            //Todos
         }
      }
      return mensajeError;
   }

   private boolean flujoTermina(Paso paso) {
      boolean evalua = false;
      boolean termina = false;
      if (!pasosValidados.contains(paso)) {
         evalua = true;
      }
      if (evalua) {
         pasosValidados.add(paso);
         if ("F".equals(paso.getTipoPaso()) && "S".equals(paso.getFinalCorrecto())) {
            return true;
         } else {
            List<Evento> eventos = paso.getEventos();
            for (Evento evento : eventos) {
               if (evento.getPasoSiguiente() != null) {
                  termina = flujoTermina(evento.getPasoSiguiente());
               }
               if (termina) {
                  break;
               } else {
                  if (evento.getPasoSiguienteMonto() != null) {
                     termina = flujoTermina(evento.getPasoSiguienteMonto());
                  }
               }
            }
         }
      }
      return termina;
   }

   @Transactional(readOnly = false)
   public void eliminarPaso(String claveFlujo, String clavePaso) {
      Paso paso = pasoDAO.obtenerPaso(claveFlujo, clavePaso);
      pasoDAO.eliminarPaso(paso);
   }

   @Transactional(readOnly = false)
   public void eliminarEvento(String claveFlujo, String clavePaso, String claveEvento) {
      Evento evento = eventoDAO.obtenerEvento(claveFlujo, clavePaso, claveEvento);
      eventoDAO.eliminarEvento(evento);
   }

   @Transactional(readOnly = false)
   public void eliminarResponsable(String claveFlujo, String clavePaso, String claveUsuario) {
      ResponsablePaso responsable = responsablePasoDAO.obtenerResponsablePaso(claveFlujo, clavePaso, claveUsuario);
      responsablePasoDAO.eliminarResponsablePaso(responsable);
   }
}
